﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Configuration;
/*********************************
 * 标题：验证码生成器
 * 描述：生成登录弹框验证码图片
 * 开发：单车上的程序猿（2014.10.24）
 * 编辑：      
 * 备注：
 * ******************************/

namespace QiBu.Api.Helper.Common
{
    /// <summary>
    /// 验证码生成器
    /// </summary>
    public class Captcha
    {
        /// <summary>
        /// 字体大小
        /// </summary>
        protected const float FontSize = 19;
        /// <summary>
        /// 字体样式
        /// </summary>
        protected static Font CodeFont = new Font("Arial", FontSize);
        /// <summary>
        /// 字体颜色（随机选择）
        /// </summary>
        protected static Color[] FontColors = new Color[] { Color.Black, Color.Orange, Color.Red, Color.RoyalBlue, Color.Chartreuse, Color.YellowGreen };
        /// <summary>
        /// 噪点颜色
        /// </summary>
        protected static Color[] NoiseColors = new Color[] { Color.LightGray, Color.LightYellow, Color.Lavender };
        /// <summary>
        /// 验证码组成字母
        /// </summary>
        protected readonly static string CaptchaChars = ConfigurationManager.AppSettings["CaptchaChars"];


        /// <summary>
        /// 
        /// </summary>
        /// <param name="length">验证码长度</param>
        public Captcha(byte length)
        {
            this.Generate(length);
        }


        /// <summary>
        /// 验证码值
        /// </summary>
        public string Value
        {
            get;
            protected set;
        }


        /// <summary>
        /// 生成验证码
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <returns>验证码</returns>
        public string Generate(byte length)
        {
            // 重置验证码值
            this.Value = String.Empty;

            Random rand = new Random();
            for (byte i = 0; i < length; i++)
            {
                this.Value += CaptchaChars[rand.Next(CaptchaChars.Length)];
            }

            return this.Value;
        }

        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="noiseAmount">噪点数</param>
        /// <param name="solid">文字厚实程度</param>
        /// <param name="range">波形弯曲的波幅</param>
        /// <param name="phase">波形弯曲的初始相位</param>
        /// <returns>验证码图片</returns>
        public Bitmap CreateImage(Color bgColor, short noiseAmount, int solid, double range, double phase)
        {
            Bitmap desImg = null;
            int codeLen = this.Value.Length;

            if (codeLen > 0)
            {
                desImg = new Bitmap((int)(FontSize * codeLen * 1.3), (int)(FontSize * 1.8));
                Bitmap tempImg = new Bitmap(desImg.Width, desImg.Height);
                Graphics gDes = Graphics.FromImage(desImg), gTemp = Graphics.FromImage(tempImg);

                Random rand = new Random();
                int xLimit = desImg.Width - 2, yLimit = desImg.Height - 2;

                // 设置背景色
                gDes.Clear(bgColor);
                gTemp.Clear(bgColor);

                // 输出验证码
                float y = 0.1F * FontSize;
                for (int i = 0; i < codeLen; i++)
                {
                    Brush brush = new SolidBrush(FontColors[rand.Next(FontColors.Length)]);
                    gTemp.DrawString(this.Value.Substring(i, 1), CodeFont, brush, (i + 0.36F) * FontSize, y);
                }

                // 添加噪点
                Pen pen;
                for (int i = 0; i < noiseAmount; i++)
                {
                    pen = new Pen(NoiseColors[rand.Next(NoiseColors.Length)]);
                    gDes.DrawRectangle(pen, rand.Next(2, xLimit), rand.Next(2, yLimit), 1, 1);
                }

                // 波浪化
                double baseAxisLen = (double)desImg.Height;
                for (int i = 0, j, bgArgb = bgColor.ToArgb(), newX, newY; i < desImg.Width; i++)
                {
                    for (j = 0; j < desImg.Height; j++)
                    {
                        // 取得当前点的颜色
                        Color color = tempImg.GetPixel(i, j);

                        if (color.A != 0 && color.ToArgb() != bgArgb && rand.Next(solid) > 0)
                        {
                            newX = i + (int)(Math.Sin((Math.PI * 2 * (double)j) / baseAxisLen + phase) * range);
                            newY = j;

                            if (newX >= 0 && newX < desImg.Width
                             && newY >= 0 && newY < desImg.Height)
                            {
                                desImg.SetPixel(newX, newY, color);
                            }
                        }
                    }
                }

                gDes.Dispose();
                gTemp.Dispose();
            }

            return desImg;
        }
    }
}
